//////////////////////////////////////////////////////////////////////////
// ImageShackAPI.h - Declaration of ImageShackAPI classes
//     
// Requires:
//   ImageShackBase.h
//   uploader/Uploader.h
//   uploader/templates.h
//   uploader/stubs.h
//   uploader/safe.h
//   templates/SmartPtr.h
//
//////////////////////////////////////////////////////////////////////////

#pragma once

#include <atlstr.h>
#include <atlcoll.h>
#include "ImageShackBase.h"

#include "uploader/Uploader.h"
#include "uploader/templates.h"

namespace API {
namespace ImageShack {

/**
 * ErrorResponse structure is used to obtain login error description.
 * See ImageShackAPI.Login().
 */
struct ErrorResponse
{
	CStringW code;
	CStringW message;
};

/**
 * Logged in User Info
 */
class IUserInfo
{
public:
    /** Returns user id */
    virtual LPCWSTR GetId() const = 0;
    /** Returns user name (can be NULL). */
    virtual LPCWSTR GetName() const = 0;
    /** Returns user cookie */
    virtual LPCWSTR GetCookie() const = 0;
};

/**
 * Upload Info
 */
struct UploadInfo
{
    /**
     * Full path to image or video file.
     * If This parameter is HTTP URL than transload method is used instead of upload.
     */
	CStringW file;

    /**
     * Optional, content-type of file.
     */
    CStringW content_type;

    /**
     * Full path to video default frame picture. Optional, used only for video upload.
     * When you uploading your video you could supply a default frame
     * that will be displayed when video is stopped.
     * Dimensions of this image should be the same as video file's ones to avoid artefacts on screen. 
     */
    CStringW thumbnail;

    /**
     * Optional, resize options for image in form WxH if image is uploaded/transloaded.
     * No impact on video uploads. 
     *
     * See SetSize(W, H) method.
     */
    CStringW size;

    /**
     * Optional, a comma-separated list of tags to add to your video/image. E.g. family,picture.
     */
    CStringW tags;

    /**
     * Developer could tell to ImageShack to leave/remove information bar on thumbnail image generated by ImageShack.
     * Default is false.
     */
    bool remove_bar;

    /**
     * Public/private marker of your video/picture.
     * Default is true.
     */
    bool is_public;
    
    UploadInfo()
        : remove_bar(false)
        , is_public(true)
    {
    }

    UploadInfo(LPCWSTR pszFile)
        : file(pszFile)
        , remove_bar(false)
        , is_public(true)
    {
    }

    /**
     * Set size parameter in form WxH
     */
    void SetSize(int width, int height)
    {
        size.Format(L"%ix%i", width, height );
    }

    // is used by uploader to show error messages
    operator CString () const
    {
        return (CString)GetFileName();
    }

    CStringW GetFileName() const
    {
        int idx = file.ReverseFind(L'\\');
        if (-1 == idx) idx = file.ReverseFind(L'/');
        return idx == -1 ? file : file.Mid(idx+1);
    }

    // fields for internal use (any value will be reset)
	CStringW devkey;   // you should put devkey to ImageShackAPI constructor
	CStringW cookie;   // you should use ImageShackAPI.SetCookie()
	CStringW username; // you should use ImageShackAPI.SetAuthInfo()
	CStringW password; //
};

/**
 * Upload Result
 */
struct UploadResult
{
    struct FileInfo
    {
        ULONGLONG size;         // size of file in bytes
        CStringW content_type;  // content-type
        CStringW file;          // short file name

        FileInfo() : size(0) {}
    };

    struct Files
    {
        CStringW server;
        CStringW bucket;

        FileInfo image;     // image of video file info
        FileInfo thumbnail; // thumbnail of file
    };

    struct Resolution
    {
        int width;
        int height;

        Resolution() : width(0), height(0) {}
    };

    struct VideoInfo
    {
        CStringW status;
        int duration;

        VideoInfo() : duration(0) {}
    };

    /**
     * Links that can be used to embed images/videos to web pages.
     */
    struct Links
    {
        CStringW image_link;
        CStringW image_html;
        CStringW image_bb;
        CStringW image_bb2;
        CStringW yfrog_link;
        CStringW yfrog_thumb;
        CStringW thumb_link;
        CStringW thumb_html;
        CStringW thumb_bb;
        CStringW thumb_bb2;
        CStringW ad_link;
        CStringW video_embed;
        CStringW done_page;
    };

    Files files;           // file and thumbnail info
    Resolution resolution; // resolution of file
    VideoInfo video_info;  // video file info
    CStringW visibility;   // "yes" for public files and "no" for private
    Links links;           // links for web pages
};

// Adopted external interfaces
typedef UPLOAD::IUniversalUploaderListener<UploadInfo, UploadResult>        UploaderListener;
typedef SmartReleasePtr<UploaderListener>                                   UploaderListenerSmartPtr;
typedef UPLOAD::IUniversalUploaderProgressListener                          ProgressListener;
typedef SmartReleasePtr<ProgressListener>                                   ProgressListenerSmartPtr;
typedef UPLOAD::IUniversalUploader<UploadInfo, UploadResult>                Uploader;
typedef SmartReleasePtr<Uploader>                                           UploaderSmartPtr;
typedef UPLOAD::IUniversalUploaderCancel                                    UploaderCancel;
typedef UPLOAD::UniversalUploaderException                                  UploaderException;
typedef UPLOAD::UniversalUploaderErrorAction                                UploaderErrorAction;
typedef UPLOAD::UniversalUploaderErrorInfo                                  UploaderErrorInfo;
typedef UPLOAD::TLIB::UniversalUploaderListenerComposite<UploadInfo, UploadResult>  UploaderListenerComposite;

// forward declaration
struct ImageShackAPIPrivate;

/**
 * ImageShack API.
 *
 * Remark: API use COM and it requires 'CoInitialize'd calling thread.
 *
 * @author Alexander Kozlov
 */
class IMAGESHACK_API ImageShackAPI
{
public:
    /**
     * ImageShackAPI constructor.
     *
     * Parameters:
     *   pszDevKey - The key is a string which identifies your application.
     *               See http://code.google.com/p/imageshackapi/wiki/DeveloperKey
     */
    ImageShackAPI(const char* pszDevKey);
    ImageShackAPI(const ImageShackAPI& );
    ~ImageShackAPI();

    /**
     * Login to ImageShack.
     * After successful login use GetUserInfo() to get user information.
     * This method will reset any parameters which were set manually using SetCookie() or SetAuthInfo()
     *
     * Parameters:
     *   pszUserName - username or email.
     *   pszPassword - user password.
     *   pError      - optional, if login failed and parameter is not NULL it will be filled with error description and code.
     */
	bool Login(LPCWSTR pszUserName, LPCWSTR pszPassword, /*out*/ ErrorResponse* pError = NULL);

    /**
     * Open Login dialog and call Login(pszUserName, pszPassword). Read description above.
     */
	bool Login();

    /**
     * Check whether user is logged in.
     * Method returns false if you use SetCookie() or SetAuthInfo() instead of Login().
     */
	bool IsLoggedIn() const;

    /**
     * Return id and cookie of the logged in user.
     * See IUserInfo above.
     */
    IUserInfo* GetUserInfo() const; 

    /**
     * Reset username/password and cookie which were set by Login(), SetCookie() and SetAuthInfo().
     */
    void Logout();

    /**
     * Set cookie without login.
     * After successful login you can save cookie (see IUserInfo) and use it in the future.
     * Useful to implement remember me functionality.
     */
    void SetCookie(LPCWSTR pszCookie);

    /**
     * Set user/password without login. It will be used during upload.
     */
    void SetAuthInfo(LPCWSTR pszUserName, LPCWSTR pszPassword);

    /**
     * Start upload/transload items in separate thread.
     * You should expect that any callback will come from another thread and you should take care of thread safety.
     *
     * Parameters:
     *   pFiles           - array of UploadInfo structures. See UploadInfo.
     *   nCount           - number of items in array
     *   uploaderListener - upload listener to track upload process.
     *                      Optional, but you should know when upload complete to avoid exceptions during exit from your application.
     *                      See default template implementation UniversalUploaderListener in stubs.h
     *   progressListener - optional, progress listener to replace default progress dialog.
     *                      See default template implementation UniversalUploaderProgressListener in stubs.h
     *
     * Exceptions:
     *   If upload cannot be started then UPLOAD::UniversalUploaderException will be thrown.
     *   For example if nCount is zero.
     */
    void UploadFiles(const UploadInfo* pFiles, UINT nCount, const UploaderListenerSmartPtr &uploaderListener = UploaderListenerSmartPtr(), const ProgressListenerSmartPtr &progressListener = ProgressListenerSmartPtr());

    void UploadFiles(const CSimpleArray<UploadInfo> &arFiles, const UploaderListenerSmartPtr &uploaderListener = UploaderListenerSmartPtr(), const ProgressListenerSmartPtr &progressListener = ProgressListenerSmartPtr())
    {
        UploadFiles(arFiles.GetData(), arFiles.GetSize(), uploaderListener, progressListener);
    }

    /**
     * Open My Images Pages in default browser.
     */
    void OpenMyImagesPage();
    /**
     * Open My Videos Pages in default browser.
     */
    void OpenMyVideosPage();

private:
    ImageShackAPIPrivate* m_pPrivate;

    ImageShackAPI& operator = (const ImageShackAPI& );
};

} // namespace ImageShack
} // namespace API

// declare mapping for builder
HTTP::MultipartFormDataRequest& operator << (HTTP::MultipartFormDataRequest&, const API::ImageShack::UploadInfo &);
// declare mapping for parser
bool operator >> (const CStringA &, API::ImageShack::UploadResult &);
bool operator >> (const CStringA &, UPLOAD::UniversalUploaderErrorInfo &);
